import * as THREE from 'three';
import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';

class modelAdd {
  constructor(data, callback) {
    this.modelData(data, callback);
  }
  modelData(data, callback) {
    let num = 0;
    let group = new THREE.Group();
    for (const item of data) {
      this.loadFbx(item, (obj) => {
        if (item.groupName) {
          group.name = item.groupName;
        }
        if (item.children) {
          this.offset(obj, item, group);
        } else {
          if (item.name) {
            obj.name = item.name;
          }
          this.rotate(obj, item);
          obj.position.set(item.x, item.y, item.z);
          group.add(obj);
        }
        num++;
        // 加载完所有执行回调
        if (data.length === num && callback) {
          callback(group);
        }
      });
    }
  }
  loadFbx(data, callback) {
    const loader = new FBXLoader();
    if (data.url instanceof Array) {
      // 把多个模型合并成组返回成一个模型
      let group = new THREE.Group();
      let count = 0;
      for (const item of data.url) {
        loader.load(item, (object) => {
          this.childAttr(object);
          group.add(object);
          count++;
          if (data.url.length === count) {
            callback(group);
          }
        });
      }
    } else {
      loader.load(data.url, (object) => {
        this.childAttr(object);
        callback(object);
      });
    }
  }
  offset(obj, item, group) {
    let clone = null;
    // 每排有多个相同模型 
    for (const list of item.children) {
      if (item.name) {
        obj.name = item.name;
      }
      if (list.offsetX) {
        for (let i = 0; i < list.num; i++) {
          clone = obj.clone();
          this.rotate(clone, list);
          clone.position.set(list.x + (i * list.offsetX), list.y, list.z);
          group.add(clone);
        }
      } else if (list.offsetY) {
        for (let i = 0; i < list.num; i++) {
          clone = obj.clone();
          this.rotate(clone, list);
          clone.position.set(list.x, list.y + (i * list.offsetY), list.z);
          group.add(clone);
        }
      } else if (list.offsetZ) {
        for (let i = 0; i < list.num; i++) {
          clone = obj.clone();
          this.rotate(clone, list);
          clone.position.set(list.x, list.y, list.z + (i * list.offsetZ));
          group.add(clone);
        }
      } else {
        clone = obj.clone();
        this.rotate(clone, list);
        clone.position.set(list.x, list.y, list.z);
        group.add(clone);
      }
    }
  }
  rotate(obj, item) {
    if (item.rotateX) {
      obj.rotateX(item.rotateX);
    }
    if (item.rotateY) {
      obj.rotateY(item.rotateY);
    }
    if (item.rotateZ) {
      obj.rotateZ(item.rotateZ);
    }
  }
  childAttr(object) {
    object.traverse((child) => {
      if (child instanceof THREE.Mesh) {
        child.material.transparent = true;
        child.material.opacity = true;
        child.castShadow = true;
        child.receiveShadow = true;
        child.material.side = THREE.DoubleSide;
      }
    });
  }
}
class modelRemove {
  constructor(scene, allObject) {
    scene.remove(allObject);
  }
}
class meshAdd {
  constructor(scene, data, callback) {
    for (const item of data) {
      item.name = new THREE.Mesh(
        new THREE.BoxGeometry(item.l, item.w, item.h),
        new THREE.MeshPhongMaterial({ flatShading: true, color: item.color, side: THREE.DoubleSide }),
      );
      item.name.position.set(item.x, item.y, item.z);
      if (item.image) {
        let texture = new THREE.TextureLoader().load(item.image);
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;
        texture.repeat.set(item.repeatX, item.repeatY);
        item.name.material = new THREE.MeshStandardMaterial({
          map: texture,
          side: THREE.DoubleSide,
        });
      }
      if (item.opacity) {
        item.name.material.opacity = item.opacity;
        item.name.material.transparent = true;
      }
      item.name.castShadow = true;
      item.name.receiveShadow = true;
      scene.add(item.name);
      if (callback) {
        callback(item.name);
      }
    } 
  }
}
class modelAnimate {
  constructor(mixer, object, time, array, callback) {
    mixer = new THREE.AnimationMixer(object);
    let clip = new THREE.AnimationClip("default", time, array);
    let AnimationAction = mixer.clipAction(clip);
    AnimationAction.setLoop(THREE.LoopOnce);
    AnimationAction.clampWhenFinished = true;
    AnimationAction.play();
    callback(mixer);
  }
}
export { modelAdd, modelRemove, modelAnimate, meshAdd }; 